/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSG_TEXGEN
#define OSG_TEXGEN 1

#include <osg/TextureAttribute>
#include <osg/Uniform>
#include <osg/State>

#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE) || defined(OSG_GL3_AVAILABLE)
    #define GL_OBJECT_LINEAR    0x2401
    #define GL_EYE_LINEAR       0x2400
    #define GL_SPHERE_MAP       0x2402
    #define GL_TEXTURE_GEN_S    0x0C60
    #define GL_TEXTURE_GEN_T    0x0C61
    #define GL_TEXTURE_GEN_R    0x0C62
    #define GL_TEXTURE_GEN_Q    0x0C63
#endif

#ifndef GL_NORMAL_MAP
    #define GL_NORMAL_MAP       0x8511
#endif

#ifndef GL_REFLECTION_MAP
    #define GL_REFLECTION_MAP   0x8512
#endif

namespace osg {

/** TexGen encapsulates the OpenGL glTexGen (texture coordinate generation)
  * state.*/
class OSG_EXPORT TexGen : public TextureAttribute
{
    public :

        TexGen();

        /** Copy constructor using CopyOp to manage deep vs shallow copy. */
        TexGen(const TexGen& texgen,const CopyOp& copyop=CopyOp::SHALLOW_COPY);

        META_StateAttribute(osg, TexGen, TEXGEN);

        /** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */
        virtual int compare(const StateAttribute& sa) const
        {
            // Check for equal types, then create the rhs variable
            // used by the COMPARE_StateAttribute_Parameter macros below.
            COMPARE_StateAttribute_Types(TexGen,sa)

            // Compare each parameter in turn against the rhs.
            COMPARE_StateAttribute_Parameter(_mode)
            COMPARE_StateAttribute_Parameter(_plane_s)
            COMPARE_StateAttribute_Parameter(_plane_t)
            COMPARE_StateAttribute_Parameter(_plane_r)
            COMPARE_StateAttribute_Parameter(_plane_q)

            return 0; // Passed all the above comparison macros, so must be equal.
        }

        virtual bool getModeUsage(StateAttribute::ModeUsage& usage) const
        {
            usage.usesTextureMode(GL_TEXTURE_GEN_S);
            usage.usesTextureMode(GL_TEXTURE_GEN_T);

            // Not happy with turning all tex gen parameters on
            // as the OSG currently only supports 2D textures and therefore
            // only S and T will be required, R&Q would be redundant...
            // So commenting out the following until OSG supports 3D textures.
            // I plan to revamp the OpenGL state management later so will
            // tidy up then.  Robert Osfield. Jan 2001.

            // The tidy up is now happening, but will have a think before
            // resolving the below parameters.

            usage.usesTextureMode(GL_TEXTURE_GEN_R);
            usage.usesTextureMode(GL_TEXTURE_GEN_Q);
            return true;
        }

        virtual void apply(State& state) const;

        enum Mode {
            OBJECT_LINEAR  = GL_OBJECT_LINEAR,
            EYE_LINEAR     = GL_EYE_LINEAR,
            SPHERE_MAP     = GL_SPHERE_MAP,
            NORMAL_MAP     = GL_NORMAL_MAP,
            REFLECTION_MAP = GL_REFLECTION_MAP
        };

        void setMode( Mode mode );

        Mode getMode() const { return _mode; }

        enum Coord {
          S, T, R, Q
        };

        void setPlane(Coord which, const Plane& plane);

        Plane& getPlane(Coord which);

        const Plane& getPlane(Coord which) const;

        /** Set the tex gen planes from specified matrix.
          * Typical usage would be to pass in a projection
          * matrix to set up projective texturing.
          */
        void setPlanesFromMatrix(const Matrixd& matrix);

    protected :

        virtual ~TexGen( void );

        std::string getUniformName(const char* baseName, unsigned int unit);

        void configureUniformNames();

        Mode _mode;

        ref_ptr<PlaneUniform> _plane_s;
        ref_ptr<PlaneUniform> _plane_t;
        ref_ptr<PlaneUniform> _plane_r;
        ref_ptr<PlaneUniform> _plane_q;

        StateSet::DefineList    _defineList;
};

}

#endif
